
// Simple Screen for the meggyjr - draw the screen from a frame buffer. 
// Eric McCreath 2012  - GLPv3

// To compile and install:

/*
avr-gcc -DF_CPU=16000000UL -mmcu=atmega328p -o graphics2.out graphics2.c
avr-objcopy -O ihex -R .eeprom graphics2.out graphics2.hex
avrdude -b57600 -patmega328p -cstk500v1 -P/dev/ttyUSB0 -U flash:w:graphics2.hex

// for windows use this to push to the Meggy Jr
avrdude -b57600 -patmega328p -cstk500v1 -PCOM3 -U flash:w:graphics2.hex
*/

#include <avr/io.h>
#include <stdlib.h>
//#include "delay.h"

uint8_t fbRed[8];
uint8_t fbGreen[8];
uint8_t fbBlue[8];
uint8_t fbLights;

uint8_t multipleLights[8];
char* colours2[8];

static int redFrequency = 1;
static int greenFrequency = 1;
static int blueFrequency = 1;

void delay(uint16_t ms)
{
   uint16_t i,j;
   uint16_t loop = F_CPU / 17000;  // this is approximate and needs calabration.
   for (i=0;i<ms;i++) {
      for (j=0;j<loop;j++);
   }
}


void SetColour(uint8_t* r, uint8_t* g, uint8_t* b, char colour[10])
{
	*r = 0;
	*g = 0;
	*b = 0;
	if (strcmp(colour, "RED") == 0)					
	{
		*r = 1;
		redFrequency = (redFrequency + 1) % 1;
	}
	else if (strcmp(colour, "GREEN") == 0)		
	{
		*g = 1;
		greenFrequency = (greenFrequency + 1) % 1;
	}
	else if (strcmp(colour, "BLUE") == 0)		
	{
		*b = 1;
		blueFrequency = (blueFrequency + 1) % 1;
	}
	else if (strcmp(colour, "YELLOW") == 0)	
	{
		*r = 1;*g = 1;
		redFrequency = (redFrequency + 1) % 1;
		greenFrequency = (greenFrequency + 1) % 2;
	}
	else if (strcmp(colour, "PURPLE") == 0)	
	{
		*r = 1;*b = 1;
		redFrequency = (redFrequency + 1) % 1;
		blueFrequency = (blueFrequency + 1) % 1;
	}
	else if (strcmp(colour, "LIGHTBLUE") == 0)	
	{
		*g = 1;*b = 1;
		greenFrequency = (greenFrequency + 1) % 1;
		blueFrequency = (blueFrequency + 1) % 1;
	}
	else if (strcmp(colour, "WHITE") == 0)		
	{
		*r = 1;*g = 1;*b = 1;
		redFrequency = (redFrequency + 1) % 1;
		greenFrequency = (greenFrequency + 1) % 1;
		blueFrequency = (blueFrequency + 1) % 1;
	}
	else if (strcmp(colour, "PINK") == 0)
	{
		*r = 1;*b = 1;
		redFrequency = (redFrequency + 1) % 1;
		blueFrequency = (blueFrequency + 1) % 3;
	}	
}

uint8_t min(uint8_t a,uint8_t b)
{
	if (a <=b)	{return a;}
	else		{return b;}
}

uint8_t max(uint8_t a,uint8_t b)
{
	if (a >=b)	{return a;}
	else		{return b;}
}

void VariableSetup()
{
   multipleLights[0] = 0x01U;
   multipleLights[1] = 0x03U;
   multipleLights[2] = 0x07U;
   multipleLights[3] = 0x0FU;
   multipleLights[4] = 0x1FU;
   multipleLights[5] = 0x3FU;
   multipleLights[6] = 0x7FU;
   multipleLights[7] = 0xFFU;
}

void initFrameBuffer()
{
   DDRB |=  (1<<PB2) | (1<<PB3); // make the serial pins output   
   PORTB |= (1<<PB2);  // set the led drivers to recieve input
 
   DDRD |= (1<<PD2); // make the pin for row 0 output
   PORTD |= (1<<PD2); // turn that row off.

   DDRD |= (1<<PD3); // row 2
   PORTD |= (1<<PD3); 

   DDRD |= (1<<PD4); // row 3
   PORTD |= (1<<PD4); 
  
   DDRD |= (1<<PD5); // row 4
   PORTD |= (1<<PD5); 

   DDRD |= (1<<PD6); // row 5
   PORTD |= (1<<PD6); 

   DDRD |= (1<<PD7); // row 6
   PORTD |= (1<<PD7); 

   DDRB |= (1<<PB0); // row 7
   PORTB |= (1<<PB0); 

   DDRB |= (1<<PB4); // row 8
   PORTB |= (1<<PB4); 
}

void drawFrameBuffer()
{
     uint8_t i;
     
     for (i=1;i<=8;i++) {
        
       SPCR = (1 << SPE) | ( 1 << MSTR );    // enable SPI, master, and set clock rate

		if (i == 1)
		{
			SPDR = fbLights; // set the shift out register
		}
		else
		{
			SPDR = 0;
		}
        while(!(SPSR & (1<<SPIF))); // wait until complete

        SPDR = fbRed[i-1]; 
        while(!(SPSR & (1<<SPIF))); 

        SPDR = fbGreen[i-1]; 
        while(!(SPSR & (1<<SPIF))); 

        SPDR = fbBlue[i-1]; 
        while(!(SPSR & (1<<SPIF))); 
        SPCR = 0; //turn off spi 


        if (i==1) {
            PORTD &= ~(1<<PD2);
        } else if (i==2) {
            PORTD &= ~(1<<PD3);
        } else if (i==3) {
            PORTD &= ~(1<<PD4);
        } else if (i==4) {
            PORTD &= ~(1<<PD5);
        } else if (i==5) {
            PORTD &= ~(1<<PD6);
        } else if (i==6) {
            PORTD &= ~(1<<PD7);
        } else if (i==7) {
            PORTB &= ~(1<<PB0);
        } else if (i==8) {
            PORTB &= ~(1<<PB4);
        }

		PORTB |= (1<<PB2);
		PORTB &= ~(1<<PB2);
        delay(1);

        if (i==1) {
            PORTD |= (1<<PD2);
        } else if (i==2) {
            PORTD |= (1<<PD3);
        } else if (i==3) {
            PORTD |= (1<<PD4);
        } else if (i==4) {
            PORTD |= (1<<PD5);
        } else if (i==5) {
            PORTD |= (1<<PD6);
        } else if (i==6) {
            PORTD |= (1<<PD7);
        } else if (i==7) {
            PORTB |= (1<<PB0);
        } else if (i==8) {
            PORTB |= (1<<PB4);
        }
     }
}

void ClearScreen()
{
	uint8_t i;
	for (i = 0; i < 8; i++)
	{
		fbRed[i] = 0x00U;
		fbGreen[i] = 0x00U;
		fbBlue[i] = 0x00U;
	}
}

void DrawPixel(uint8_t x, uint8_t y, char colour[10])
{
	uint8_t r,g,b;
	SetColour(&r, &g, &b, colour);
	
	if (redFrequency == 0) 
		if (r) {fbRed[x]   |= 1 << y;}
	if (greenFrequency == 0) 
		if (g) {fbGreen[x] |= 1 << y;}
	if (blueFrequency == 0)
		if (b) {fbBlue[x]  |= 1 << y;}
}

void DrawColumn(uint8_t x, char colour[10])
{
	uint8_t r,g,b;
	SetColour(&r, &g, &b, colour);
	
	uint8_t i;
	if (redFrequency == 0) 
		if (r) {fbRed[x]   |= 0xff;}
	if (greenFrequency == 0) 
		if (g) {fbGreen[x] |= 0xff;}
	if (blueFrequency == 0) 
		if (b) {fbBlue[x]  |= 0xff;}
}

void DrawRow(uint8_t y, char colour[10])
{
	uint8_t r,g,b;
	SetColour(&r, &g, &b, colour);
	
	uint8_t i;
	for (i = 0; i < 8; i++){	
		if (redFrequency == 0) 
			if (r) {fbRed[i]   |= 1 << y;}
		if (greenFrequency == 0) 
			if (g) {fbGreen[i] |= 1 << y;}
		if (blueFrequency == 0) 
			if (b) {fbBlue[i]  |= 1 << y;}
	}
}

void DrawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, char colour[10])
{
	int16_t dx = abs(x1-x2);
	int16_t dy = abs(y1-y2);
	int8_t sx, sy;

	if (x1 < x2) sx = 1;
	else 			   sx = -1;

	if (y1 < y2) sy = 1;
	else 			   sy = -1;
	
	int8_t err = dx - dy;
	int16_t err2;

	DrawPixel(x1, y1, colour);
	while(x1 != x2 || y1 != y2) 
	{
		err2 = 2*err;
		if (err2 > -dy) 
		{
			err -= dy;
			x1 += sx;
		}
		if (err2 < dx) 
		{
			err += dx;
			y1 += sy;
		}
		DrawPixel(x1, y1, colour); 
	} 
}

void DrawRect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, char colour[10])
{
	uint8_t r,g,b;
	SetColour(&r, &g, &b, colour);
	
	uint8_t fromBottom = min(y1,y2);
	uint8_t height = abs(y1 - y2);
	uint8_t fromRight = min(x1,x2);
	uint8_t fromLeft = max(x1,x2);
	uint8_t i;
	for (i = fromRight; i <= fromLeft; i ++)
	{
		if (redFrequency == 0) 
			if (r) {fbRed[i]   |= multipleLights[height] << fromBottom;}
		if (greenFrequency == 0) 
			if (g) {fbGreen[i] |= multipleLights[height] << fromBottom;}
		if (blueFrequency == 0) 
			if (b) {fbBlue[i]  |= multipleLights[height] << fromBottom;}
	}
}

void DrawSpaceInvader1(char colour[10])
{
	uint8_t r,g,b;
	SetColour(&r, &g, &b, colour);

	if (r && redFrequency == 0)
	{
		fbRed[0] = 0x19U;
		fbRed[1] = 0x3aU;
		fbRed[2] = 0x6dU;
		fbRed[3] = 0xfaU;
		fbRed[4] = 0xfaU;
		fbRed[5] = 0x6dU;
		fbRed[6] = 0x3aU;
		fbRed[7] = 0x19U;
	}
	if (g && greenFrequency == 0)
	{
		fbGreen[0] = 0x19U;
		fbGreen[1] = 0x3aU;
		fbGreen[2] = 0x6dU;
		fbGreen[3] = 0xfaU;
		fbGreen[4] = 0xfaU;
		fbGreen[5] = 0x6dU;
		fbGreen[6] = 0x3aU;
		fbGreen[7] = 0x19U;
	}
	if (b && blueFrequency == 0)
	{
		fbBlue[0] = 0x19U;
		fbBlue[1] = 0x3aU;
		fbBlue[2] = 0x6dU;
		fbBlue[3] = 0xfaU;
		fbBlue[4] = 0xfaU;
		fbBlue[5] = 0x6dU;
		fbBlue[6] = 0x3aU;
		fbBlue[7] = 0x19U;
	}
}

void DrawSpaceInvader2(char colour[10])
{
	uint8_t r,g,b;
	SetColour(&r, &g, &b, colour);

	if (redFrequency == 0) if (r)
	{
		fbRed[0] = 0x1aU;
		fbRed[1] = 0x3dU;
		fbRed[2] = 0x68U;
		fbRed[3] = 0xfcU;
		fbRed[4] = 0xfcU;
		fbRed[5] = 0x68U;
		fbRed[6] = 0x3dU;
		fbRed[7] = 0x1aU;
	}
	if (greenFrequency == 0) if (g)
	{
		fbGreen[0] = 0x1aU;
		fbGreen[1] = 0x3dU;
		fbGreen[2] = 0x68U;
		fbGreen[3] = 0xfcU;
		fbGreen[4] = 0xfcU;
		fbGreen[5] = 0x68U;
		fbGreen[6] = 0x3dU;
		fbGreen[7] = 0x1aU;
	}
	if (blueFrequency == 0) if (b)
	{
		fbBlue[0] = 0x1aU;
		fbBlue[1] = 0x3dU;
		fbBlue[2] = 0x68U;
		fbBlue[3] = 0xfcU;
		fbBlue[4] = 0xfcU;
		fbBlue[5] = 0x68U;
		fbBlue[6] = 0x3dU;
		fbBlue[7] = 0x1aU;
	}
}

void DrawPlane(char colour[10])
{
	uint8_t r,g,b;
	SetColour(&r, &g, &b, colour);

	if (redFrequency == 0) if (r)
	{
		fbRed[0] = 0x18U;
		fbRed[1] = 0x31U;
		fbRed[2] = 0x73U;
		fbRed[3] = 0xFFU;
		fbRed[4] = 0xFFU;
		fbRed[5] = 0x73U;
		fbRed[6] = 0x31U;
		fbRed[7] = 0x18U;
	}
	if (greenFrequency == 0) if (g)
	{
		fbGreen[0] = 0x18U;
		fbGreen[1] = 0x31U;
		fbGreen[2] = 0x73U;
		fbGreen[3] = 0xFFU;
		fbGreen[4] = 0xFFU;
		fbGreen[5] = 0x73U;
		fbGreen[6] = 0x31U;
		fbGreen[7] = 0x18U;
	}
	if (blueFrequency == 0) if (b)
	{
		fbBlue[0] = 0x18U;
		fbBlue[1] = 0x31U;
		fbBlue[2] = 0x73U;
		fbBlue[3] = 0xFFU;
		fbBlue[4] = 0xFFU;
		fbBlue[5] = 0x73U;
		fbBlue[6] = 0x31U;
		fbBlue[7] = 0x18U;
	}
}
